﻿/// Copyright (c) Microsoft Corporation.  All rights reserved.
// TcvtVsPackage.cs : Implementation of TcvtVsPackage
//

using System;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.ComponentModel.Design;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio;
using System.Security.Permissions;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.Build.Client;
using System.Reflection;
using System.IO;
using System.Collections.Generic;
using Microsoft.VisualStudio.OLE.Interop;
using System.Windows.Forms;
using EnvDTE80;
using MsVsShell = Microsoft.VisualStudio.Shell;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace Tcvt.Packages
{
    /// <summary>
    /// This is the class that implements the package exposed by this assembly.
    ///
    /// The minimum requirement for a class to be considered a valid package for Visual Studio
    /// is to implement the IVsPackage interface and register itself with the shell.
    /// This package uses the helper classes defined inside the Managed Package Framework (MPF)
    /// to do it: it derives from the Package class that provides the implementation of the 
    /// IVsPackage interface and uses the registration attributes defined in the framework to 
    /// register itself and its components with the shell.
    /// </summary>
    // This attribute tells the registration utility (regpkg.exe) that this class needs
    // to be registered as package.
    [PackageRegistration(UseManagedResourcesOnly = true)]
    // A Visual Studio component can be registered under different regitry roots; for instance
    // when you debug your package you want to register it in the experimental hive. This
    // attribute specifies the registry root to use if no one is provided to regpkg.exe with
    // the /root switch.
    [DefaultRegistryRoot("Software\\Microsoft\\VisualStudio\\10.0")]
    //[DefaultRegistryRoot("SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\9.0")]
    // This attribute is used to register the informations needed to show the this package
    // in the Help/About dialog of Visual Studio.
    //[InstalledProductRegistration(false, "#20", "#30", "1.0", IconResourceID = 400)]
    [InstalledProductRegistration(true, null, null, null)]
    // In order be loaded inside Visual Studio in a machine that has not the VS SDK installed, 
    // package needs to have a valid load key (it can be requested at 
    // http://msdn.microsoft.com/vstudio/extend/). This attributes tells the shell that this 
    // package has a load key embedded in its resources.
    //[ProvideLoadKey("Standard", "1.0.0.0", "Team Build Power Tool", "Microsoft", 10)]
    [ProvideLoadKey("Standard", "2.0", "TFS Extensions", "Microsoft", 10)]
    // This attribute is needed to let the shell know that this package exposes some menus.
    [ProvideMenuResource(1000, 1)]
    [ProvideOptionPage(typeof(Options), "TFS Check-in Validation Tools", 
        "General",
        5001,
        5002,
        true)]
    [ProvideOptionPage(typeof(BuildOptions), "TFS Check-in Validation Tools",
        "Build and Buddy Build",
        5003,
        5004,
        true)]
    [ProvideOptionPage(typeof(MiscOptions), "TFS Check-in Validation Tools",
        "Miscellaneous",
        5005,
        5006,
        true)]
    [ProvideOptionPage(typeof(CheckinNotesOptions), "TFS Check-in Validation Tools",
        "Check-in Notes",
        5007,
        5008,
        true)]
    [ProvideOptionPage(typeof(CustomMsbuildParamterOptions), "TFS Check-in Validation Tools",
        "Custom MSBuild Properties",
        5009,
        5010,
        true)]
    [ProvideOptionPage(typeof(WorkItemExplorerGeneralOptions), "Work Item Explorer",
        "General",
        5030,
        5031,
        true)]

    //Constant Value Description 
    //vsWindowKindAutoLocals {F2E84780-2AF1-11D1-A7FA-00A0C9110051} The Debugger window. 
    //vsWindowKindCallStack {0504FF91-9D61-11D0-A794-00A0C9110051} The Call Stack window. 
    //vsWindowKindClassView {C9C0AE26-AA77-11D2-B3F0-0000F87570EE} The ClassView window. 
    //vsWindowKindCommandWindow {28836128-FC2C-11D2-A433-00C04F72D18A} The Command window. 
    //vsWindowKindDocumentOutline {25F7E850-FFA1-11D0-B63F-00A0C922E851} The Document Outline window. 
    //vsWindowKindDynamicHelp {66DBA47C-61DF-11D2-AA79-00C04F990343} The Dynamic Help window. 
    //vsWindowKindFindReplace {CF2DDC32-8CAD-11D2-9302-005345000000} The Find Replace dialog box. 
    //vsWindowKindFindResults1 {0F887920-C2B6-11D2-9375-0080C747D9A0} The Find Results 1 window. 
    //vsWindowKindFindResults2 {0F887921-C2B6-11D2-9375-0080C747D9A0} The Find Results 2 window. 
    //vsWindowKindFindSymbol {53024D34-0EF5-11D3-87E0-00C04F7971A5} The Find Symbol dialog box. 
    //vsWindowKindFindSymbolResults {68487888-204A-11D3-87EB-00C04F7971A5} The Find Symbol Results window. 
    //vsWindowKindLinkedWindowFrame {9DDABE99-1D02-11D3-89A1-00C04F688DDE} A linked window frame. 
    //vsWindowKindLocals {9DDABE99-1D02-11D3-89A1-00C04F688DDE} The Debugger window. 
    //vsWindowKindMacroExplorer {07CD18B4-3BA1-11D2-890A-0060083196C6} The Macro Explorer window. 
    //vsWindowKindMainWindow {9DDABE98-1D02-11D3-89A1-00C04F688DDE} The Visual Studio .NET IDE window. 
    //vsWindowKindObjectBrowser {269A02DC-6AF8-11D3-BDC4-00C04F688E50} The Object Browser window. 
    //vsWindowKindOutput {34E76E81-EE4A-11D0-AE2E-00A0C90FFFC3} The Output Window. 
    //vsWindowKindProperties {EEFA5220-E298-11D0-8F78-00A0C9110057} The Properties window. 
    //vsWindowKindResourceView {2D7728C2-DE0A-45b5-99AA-89B609DFDE73} The Resource Editor. 
    //vsWindowKindServerExplorer {74946827-37A0-11D2-A273-00C04F8EF4FF} The Server Explorer window. 
    //vsWindowKindSolutionExplorer {3AE79031-E1BC-11D0-8F78-00A0C9110057} The Solution Explorer window. 
    //vsWindowKindTaskList {3AE79031-E1BC-11D0-8F78-00A0C9110057} The TaskList window. 
    //vsWindowKindThread {E62CE6A0-B439-11D0-A79D-00A0C9110051} The Debugger window. 
    //vsWindowKindToolbox {B1E99781-AB81-11D0-B683-00AA00A3EE26} The Toolbox. 
    //vsWindowKindWatch {90243340-BD7A-11D0-93EF-00A0C90F2734} The Watch window. 
    //vsWindowKindWebBrowser {E8B06F52-6D01-11D2-AA7D-00C04F990343} A web browser window hosted in Visual Studio .NET. 
    [MsVsShell.ProvideToolWindow(typeof(WorkItemExplorerPane), MultiInstances = false, Style = VsDockStyle.Tabbed, PositionX = 0, PositionY = 0, Width = 900, Height = 750, Transient = false, Orientation = ToolWindowOrientation.Left, Window = "9DDABE98-1D02-11D3-89A1-00C04F688DDE")]
    [MsVsShell.ProvideToolWindow(typeof(WorkItemPane), MultiInstances = true, Style = VsDockStyle.Tabbed, PositionX = 0, PositionY = 0, Width = 900, Height = 750, Transient = true, Orientation = ToolWindowOrientation.Left, Window = "9DDABE98-1D02-11D3-89A1-00C04F688DDE")]
    [ComVisible(true)]
    [Guid(GuidList.guidTfsBuggerVSPackagePkgString)]
    public sealed class TcvtVsPackage : Package, IVsInstalledProduct
    {
        //private TeamFoundationServer _tfs;
        //private VersionControlServer _versionControl;
        private Options _options;
        private BuildOptions _buildOptions;
        private MiscOptions _miscOptions;
        private CheckinNotesOptions _checkinNotesOptions;
        private CustomMsbuildParamterOptions _customMsbuildParamterOptions;
        private WorkItemExplorerGeneralOptions _workItemExplorerGeneralOptions;

        /// <summary>
        /// Default constructor of the package.
        /// Inside this method you can place any initialization code that does not require 
        /// any Visual Studio service because at this point the package object is created but 
        /// not sited yet inside Visual Studio environment. The place to do all the other 
        /// initialization is the Initialize method.
        /// </summary>
        public TcvtVsPackage()
        {
            Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "TcvtVsPackage::Constructor: Entering constructor for: {0}", this.ToString()));
            Application.EnableVisualStyles();
            Trace.WriteLine("TcvtVsPackage::Constructor: Enabled visual styles.");
        }



        /////////////////////////////////////////////////////////////////////////////
        // Overriden Package Implementation
        #region Package Members

        /// <summary>
        /// Initialization of the package; this method is called right after the package is sited, so this is the place
        /// where you can put all the initilaization code that rely on services provided by VisualStudio.
        /// </summary>
        [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        protected override void Initialize()
        {
            Trace.WriteLine (string.Format(CultureInfo.CurrentCulture, "Entering Initialize() method of: {0}", this.ToString()));
            base.Initialize();

            // Add our command handlers for menu (commands must exist in the .vsct file)
            OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
            if ( null != mcs )
            {
                // Create the command for the buddy build menu item.
                CommandID menuCommandID = new CommandID(GuidList.guidTfsBuggerVSPackageCmdSet, PkgCmdIDList.IDCommandBuddyBuild);
                //MenuCommand menuItem = new MenuCommand(MenuItemCallback, menuCommandID );
                OleMenuCommand menuItem = new OleMenuCommand(new EventHandler(BuddyBuildMenuItemCallback), menuCommandID);
                mcs.AddCommand( menuItem );

                // Create the command for the normal build menu item.
                menuCommandID = new CommandID(GuidList.guidTfsBuggerVSPackageCmdSet, PkgCmdIDList.IDCommandNormalBuild);
                menuItem = new OleMenuCommand(new EventHandler(BuildMenuItemCallback), menuCommandID);
                mcs.AddCommand(menuItem);

                // Create the command for the settings menu item.
                menuCommandID = new CommandID(GuidList.guidTfsBuggerVSPackageCmdSet, PkgCmdIDList.IDCommandSettings);
                menuItem = new OleMenuCommand(new EventHandler(SettingsMenuItemCallback), menuCommandID);
                mcs.AddCommand(menuItem);

                // Create the command for the check updates menu item.
                menuCommandID = new CommandID(GuidList.guidTfsBuggerVSPackageCmdSet, PkgCmdIDList.IDCommandCheckUpdates);
                menuItem = new OleMenuCommand(new EventHandler(CheckUpdatesMenuItemCallback), menuCommandID);
                mcs.AddCommand(menuItem);

                // Create the command for the website menu item.
                menuCommandID = new CommandID(GuidList.guidTfsBuggerVSPackageCmdSet, PkgCmdIDList.IDCommandWebsite);
                menuItem = new OleMenuCommand(new EventHandler(WebsiteMenuItemCallback), menuCommandID);
                mcs.AddCommand(menuItem);

                // Create the command for the about menu item.
                menuCommandID = new CommandID(GuidList.guidTfsBuggerVSPackageCmdSet, PkgCmdIDList.IDCommandAbout);
                menuItem = new OleMenuCommand(new EventHandler(AboutMenuItemCallback), menuCommandID);
                mcs.AddCommand(menuItem);

                // Create the command for the about work item explorer item.
                menuCommandID = new CommandID(GuidList.guidTfsBuggerVSPackageCmdSet, PkgCmdIDList.IDCommandWorkItemExplorer);
                menuItem = new OleMenuCommand(new EventHandler(WorkItemExplorerMenuItemCallback), menuCommandID);
                mcs.AddCommand(menuItem);
            }
            Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "Exiting Initialize() of: {0}", this.ToString()));
        }
        #endregion

        #region IVsInstalledProduct Members
        /// <summary>
        /// This method is called during Devenv /Setup to get the bitmap to
        /// display on the splash screen for this package.
        /// </summary>
        /// <param name="pIdBmp">The resource id corresponding to the bitmap to display on the splash screen</param>
        /// <returns>HRESULT, indicating success or failure</returns>
        /// <remarks>
        /// This is not used anymore post VS2005. IdIcoLogoForAboutbox is 
        /// used instead.
        /// </remarks>
        public int IdBmpSplash(out uint pIdBmp)
        {
            pIdBmp = 300;

            return VSConstants.S_OK;
            //return VSConstants.E_NOTIMPL;
        }

        /// <summary>
        /// This method is called to get the icon that will be displayed in the
        /// Help About dialog when this package is selected.
        /// </summary>
        /// <param name="pIdIco">The resource id corresponding to the icon to display on the Help About dialog</param>
        /// <returns>HRESULT, indicating success or failure</returns>
        public int IdIcoLogoForAboutbox(out uint pIdIco)
        {
            pIdIco = 400;

            return VSConstants.S_OK;
        }

        /// <summary>
        /// This methods provides the product official name, it will be
        /// displayed in the help about dialog.
        /// </summary>
        /// <param name="pbstrName">Out parameter to which to assign the product name</param>
        /// <returns>HRESULT, indicating success or failure</returns>
        public int OfficialName(out string pbstrName)
        {
            pbstrName = Resources._20; // GetResourceString("@2");
            return VSConstants.S_OK;
        }

        /// <summary>
        /// This methods provides the product description, it will be
        /// displayed in the help about dialog.
        /// </summary>
        /// <param name="pbstrProductDetails">Out parameter to which to assign the description of the package</param>
        /// <returns>HRESULT, indicating success or failure</returns>
        public int ProductDetails(out string pbstrProductDetails)
        {
            pbstrProductDetails = Resources._30; //GetResourceString("@3");
            return VSConstants.S_OK;
            //return VSConstants.E_NOTIMPL;
        }

        /// <summary>
        /// This methods provides the product version, it will be
        /// displayed in the help about dialog.
        /// </summary>
        /// <param name="pbstrPID">Out parameter to which to assign the version number</param>
        /// <returns>HRESULT, indicating success or failure</returns>
        public int ProductID(out string pbstrPID)
        {
            pbstrPID = Resources._50; //GetResourceString("@5");
            return VSConstants.S_OK;
            //return VSConstants.E_NOTIMPL;
        }

        #endregion

        private void CheckUpdatesMenuItemCallback(object sender, EventArgs e)
        {
            MainForm.CheckForUpdates(false);
        }

        private void WebsiteMenuItemCallback(object sender, EventArgs e)
        {
            MainForm.ShowWebsite();
        }

        private void AboutMenuItemCallback(object sender, EventArgs e)
        {
            MainForm.ShowAboutDialog();
        }

        /// <summary>
        /// This function is the callback used to execute a command when the a menu item is clicked.
        /// See the Initialize method to see how the menu item is associated to this function using
        /// the OleMenuCommandService service and the MenuCommand class.
        /// </summary>
        private void BuddyBuildMenuItemCallback(object sender, EventArgs e)
        {
            if (!this.InitializeOptions())
                return;

            MainForm shelvesetsForm = new MainForm();
            //shelvesetsForm.Tfs = _tfs;
            //shelvesetsForm.VersionControl = _versionControl;
            shelvesetsForm.ParentPackage = this;
            shelvesetsForm.BuildType = BuildValidationType.BuddyBuild;
            shelvesetsForm.ShowDialog();
            if (shelvesetsForm.BuildSuccessfullyQueued)
            {
                // show the build queue page.
            }
            return;
        }

        /// <summary>
        /// This function is the callback used to execute a command when the a menu item is clicked.
        /// See the Initialize method to see how the menu item is associated to this function using
        /// the OleMenuCommandService service and the MenuCommand class.
        /// </summary>
        private void BuildMenuItemCallback(object sender, EventArgs e)
        {
            if (!this.InitializeOptions())
                return;

            MainForm shelvesetsForm = new MainForm();
            //shelvesetsForm.Tfs = _tfs;
            //shelvesetsForm.VersionControl = _versionControl;
            shelvesetsForm.ParentPackage = this;
            shelvesetsForm.BuildType = BuildValidationType.Build;
            shelvesetsForm.ShowDialog();
            if (shelvesetsForm.BuildSuccessfullyQueued)
            {
                // TODO: show the build queue page.
            }
            return;
        }

        /// <summary>
        /// This function is the callback used to execute a command when the a menu item is clicked.
        /// See the Initialize method to see how the menu item is associated to this function using
        /// the OleMenuCommandService service and the MenuCommand class.
        /// </summary>
        private void SettingsMenuItemCallback(object sender, EventArgs e)
        {
            if (!this.InitializeOptions())
                return;

            this.ShowOptionPage(typeof(Options));
            
            return;
        }

        private void WorkItemExplorerMenuItemCallback(object sender, EventArgs e)
        {
            Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "TcvtVsPackage: Entering WorkItemExplorerMenuItemCallback."));

            ToolWindowPane pane = this.FindToolWindow(typeof(WorkItemExplorerPane), 0, true);
            //ToolWindowPane pane = this.CreateToolWindow(typeof(WorkItemExplorerPane), 0);

            if (pane == null)
            {
                throw new COMException("Failed to initialize Work Item Explorer: Pane was null.");
            }

            pane.BitmapResourceID = 500;
            pane.BitmapIndex = 3;
            ((WorkItemExplorerPane)pane).TcvtPackage = this;

            IVsWindowFrame frame = pane.Frame as IVsWindowFrame;
            if (frame == null)
            {
                throw new COMException("Failed to initialize Work Item Explorer: Frame was null.");
            }

            // Bring the tool window to the front and give it focus
            ErrorHandler.ThrowOnFailure(frame.Show());

            Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "TcvtVsPackage: Exiting WorkItemExplorerMenuItemCallback."));
        }

        /// <summary>
        /// This method loads a localized string based on the specified resource.
        /// </summary>
        /// <param name="resourceName">Resource to load</param>
        /// <returns>String loaded for the specified resource</returns>
        public string GetResourceString(string resourceName)
        {
            string resourceValue;
            IVsResourceManager resourceManager = (IVsResourceManager)GetService(typeof(SVsResourceManager));
            if (resourceManager == null)
            {
                throw new InvalidOperationException("TcvtVsPackage: Could not get SVsResourceManager service. Make sure the package is Sited before calling this method");
            }
            Guid packageGuid = this.GetType().GUID;
            int hr = resourceManager.LoadResourceString(ref packageGuid, -1, resourceName, out resourceValue);
            Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(hr);
            return resourceValue;
        }

        internal bool InitializeOptions()
        {
            try
            {
                _workItemExplorerGeneralOptions = (WorkItemExplorerGeneralOptions)this.GetDialogPage(typeof(WorkItemExplorerGeneralOptions));
                if (_workItemExplorerGeneralOptions == null)
                {
                    Utils.LogMessage(string.Format(CultureInfo.CurrentCulture, "TcvtVsPackage::InitializeOptions: Failed to retrieve general work item explorer settings."));
                    Utils.ShowErrorMessageBox(string.Format(CultureInfo.CurrentCulture, "Failed to retrieve general work item explorer settings."));
                    return false;
                }

                _options = (Options)this.GetDialogPage(typeof(Options));
                if (_options == null)
                {
                    Utils.LogMessage(string.Format(CultureInfo.CurrentCulture, "TcvtVsPackage::InitializeOptions: Failed to retrieve general settings."));
                    Utils.ShowErrorMessageBox(string.Format(CultureInfo.CurrentCulture, "Failed to retrieve general settings."));
                    return false;
                }

                _buildOptions = (BuildOptions)this.GetDialogPage(typeof(BuildOptions));
                if (_buildOptions == null)
                {
                    Utils.LogMessage(string.Format(CultureInfo.CurrentCulture, "TcvtVsPackage::InitializeOptions: Failed to retrieve build settings."));
                    Utils.ShowErrorMessageBox(string.Format(CultureInfo.CurrentCulture, "Failed to retrieve build settings."));
                    return false;
                }

                _miscOptions = (MiscOptions)this.GetDialogPage(typeof(MiscOptions));
                if (_miscOptions == null)
                {
                    Utils.LogMessage(string.Format(CultureInfo.CurrentCulture, "TcvtVsPackage::InitializeOptions: Failed to retrieve miscellaneous settings."));
                    Utils.ShowErrorMessageBox(string.Format(CultureInfo.CurrentCulture, "Failed to retrieve miscellaneous settings."));
                    return false;
                }

                _checkinNotesOptions = (CheckinNotesOptions)this.GetDialogPage(typeof(CheckinNotesOptions));
                if (_checkinNotesOptions == null)
                {
                    Utils.LogMessage(string.Format(CultureInfo.CurrentCulture, "TcvtVsPackage::InitializeOptions: Failed to retrieve check-in notes settings."));
                    Utils.ShowErrorMessageBox(string.Format(CultureInfo.CurrentCulture, "Failed to retrieve check-in notes settings."));
                    return false;
                }

                _customMsbuildParamterOptions = (CustomMsbuildParamterOptions)this.GetDialogPage(typeof(CustomMsbuildParamterOptions));
                if (_customMsbuildParamterOptions == null)
                {
                    Utils.LogMessage(string.Format(CultureInfo.CurrentCulture, "TcvtVsPackage::InitializeOptions: Failed to retrieve custom MSBuild parameter settings."));
                    Utils.ShowErrorMessageBox(string.Format(CultureInfo.CurrentCulture, "Failed to retrieve custom MSBuild parameter settings."));
                    return false;
                }
                _customMsbuildParamterOptions.BuddyBuildOptionsDialog = _buildOptions;
                _customMsbuildParamterOptions.MiscellaneousOptionsDialog = _miscOptions;
                //if (_customMsbuildParamterOptions.Properties == null || _customMsbuildParamterOptions.Properties.Length == 0)
                _customMsbuildParamterOptions.PopulatePropertiesGrid();

                return true;
            }
            catch (Exception ex)
            {
                Utils.LogMessage(string.Format("TcvtVsPackage::InitializeOptions: Error retrieving settings: Message: {0}", ex.Message), LogType.Error);
                Utils.LogMessage(string.Format("TcvtVsPackage::InitializeOptions: Error retrieving settings: {0}", ex.StackTrace), LogType.Error);
                Utils.ShowErrorMessageBox(string.Format("Error retrieving settings:\r\n\r\n{0}",
                    ex.Message));
                //Utils.ShowErrorMessageBox(string.Format("Error retrieving settings:\r\n\r\n{0}\r\n{1}",
                //    ex.Message,
                //    ex.StackTrace));
                return false;
            }
        }

        public Options GeneralOptions
        {
            get
            {
                return _options;
            }
            set
            {
                _options = value;
            }
        }

        public BuildOptions BuildAndBuddyBuildOptions
        {
            get
            {
                return _buildOptions;
            }
            set
            {
                _buildOptions = value;
            }
        }

        public MiscOptions MiscellaneousOptions
        {
            get
            {
                return _miscOptions;
            }
            set
            {
                _miscOptions = value;
            }
        }

        public CheckinNotesOptions CheckinNotesValuesOptions
        {
            get
            {
                return _checkinNotesOptions;
            }
            set
            {
                _checkinNotesOptions = value;
            }
        }

        public CustomMsbuildParamterOptions MsbuildParamterOptions
        {
            get
            {
                return _customMsbuildParamterOptions;
            }
            set
            {
                _customMsbuildParamterOptions = value;
            }
        }

        public WorkItemExplorerGeneralOptions WorkItemExplorerGeneralOptions
        {
            get
            {
                return _workItemExplorerGeneralOptions;
            }
            set
            {
                _workItemExplorerGeneralOptions = value;
            }
        }
    }
}